package com.cssw.fyzb.busi.util;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;

/**
 * 3Des 加密/解密
 *
 * @author Feng Chen
 */
public abstract class TripleDesUtil {

    private static final int KEY_LENGTH = 24;

    private TripleDesUtil() {
        // Prevent Instantiation
    }

    /**
     * 加密
     *
     * @param key       密钥
     * @param plainText 明文
     * @return 密文
     * @throws Exception
     */
    public static byte[] encrypt(String key, String plainText) throws Exception {
        Cipher cipher = newCipher(key, Cipher.ENCRYPT_MODE);
        return cipher.doFinal(plainText.getBytes("UTF-8"));
    }

    /**
     * 解密
     *
     * @param key        密钥
     * @param cipherText 密文
     * @return 明文
     * @throws Exception
     */
    public static String decrypt(String key, byte[] cipherText) throws Exception {
        Cipher cipher = newCipher(key, Cipher.DECRYPT_MODE);
        return new String(cipher.doFinal(cipherText), "UTF-8");
    }

    // SECTION : INNER HELPER

    private static Cipher newCipher(String key, int mode)
            throws InvalidKeyException, NoSuchAlgorithmException,
            InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException {
        if (key.length() > KEY_LENGTH) {
            throw new IllegalArgumentException("Key length must be less than 24.");
        }

        // 填充密钥到24位
        key = padKey(key);
        byte[] keyValue = key.getBytes();
        DESedeKeySpec keySpec = new DESedeKeySpec(keyValue);
        SecretKey secretKey = SecretKeyFactory.getInstance("DESede").generateSecret(keySpec);
        Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
        cipher.init(mode, secretKey, new IvParameterSpec(new byte[8]));
        return cipher;
    }

    private static String padKey(String key) {
        StringBuilder builder = new StringBuilder(key);
        while (builder.length() < KEY_LENGTH) {
            builder.append(" ");
        }
        return builder.toString();
    }


}
